/**
 * Copyright 2005 SIB Framework

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
 */

package org.sibframework.utils;


import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;


public class DomTool {

	
	/**
	 * @param doc
	 *            the XML document to write to file
	 * @param file
	 *            the file full path and name to write.
	 * @throws TransformerException
	 *             a
	 * @throws IOException exception
	 */
	public final void writeDom(final Document doc, final File file)
			throws TransformerException, IOException {
		//DOMSource doms = new DOMSource(doc);
		FileOutputStream fos = new FileOutputStream(file);

		writeDom(doc, fos);
		fos.close();

	}

	/**
	 * @param doc
	 *            the XML document to write to file
	 * @param os
	 *            the output stream to write.
	 * @throws TransformerException
	 *             ad
	 */
	public final void writeDom(final Document doc, final OutputStream os)
			throws TransformerException {
		DOMSource doms = new DOMSource(doc);

		StreamResult sr = new StreamResult(new BufferedOutputStream(os));
		TransformerFactory tf = TransformerFactory.newInstance();
		Transformer t = tf.newTransformer();
		t.transform(doms, sr);

	}

	/**
	 * @param xmlFile
	 *            xml file to read
	 * @return the xml document object.
	 * @throws ParserConfigurationException
	 *             can't find xml parser.
	 * @throws IOException
	 *             can't read file
	 * @throws SAXException
	 *             parse error
	 */
	public final Document readDom(final File xmlFile) 
	throws ParserConfigurationException, SAXException, IOException {
		Document doc = null;
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		DocumentBuilder db = dbf.newDocumentBuilder();
		doc = db.parse(xmlFile);
		return doc;
	}

	/**
	 * @param xmlFile
	 *            xml file InputStream to read
	 * @return the xml document object.
	 * @throws ParserConfigurationException
	 *             can't find xml parser.
	 * @throws IOException
	 *             can't read file
	 * @throws SAXException
	 *             parse error
	 */
	public final Document readDom(final InputStream xmlFile)
			throws ParserConfigurationException, SAXException, IOException {
		Document doc = null;
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		DocumentBuilder db = dbf.newDocumentBuilder();
		doc = db.parse(xmlFile);
		return doc;
	}

	/**
	 * @return a new Document
	 * @throws ParserConfigurationException
	 *             paser exception
	 */
	public final Document createDom() throws ParserConfigurationException {
		Document doc = null;
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		DocumentBuilder db = dbf.newDocumentBuilder();
		doc = db.newDocument();
		return doc;
	}

	/**
	 * @param element
	 *            the element to be the file parent
	 * @param file
	 *            the xml file object to be append
	 * @throws ParserConfigurationException
	 *             parser exception
	 * @throws SAXException
	 *             sax exception
	 * @throws IOException
	 *             io exception
	 */
	public final void appendFile(final Element element, final File file)
			throws ParserConfigurationException, SAXException, IOException {
		Document doc = element.getOwnerDocument();
		String filename = file.getName();
		Element fileNode = doc.createElement(filename.substring(0, file.getName().lastIndexOf(".")));
		//fileNode.setAttribute("fileName", filename);
		fileNode.setAttribute("lastModifide", new SimpleDateFormat(
				"yyyy-MM-dd HH:mm:ss").format(new Date(file.lastModified())));
		Document srcdoc = this.readDom(file);
		Node node = doc.importNode(srcdoc.getDocumentElement().cloneNode(true),
				true);
		fileNode.appendChild(node);
		element.appendChild(fileNode);
	}

	public final Node anySubNode(final Node srcDom, final String subpath) {
		String[] paths = subpath.split("\\.");
		Node targetNode = srcDom;
		for (int i=0; i < paths.length && targetNode != null; i++) {
			targetNode = subNode(targetNode, paths[i]);
		}
		return targetNode;
	}
	
	public final Node subNode(final Node srcDom, final String tagName) {
		NodeList nl = srcDom.getChildNodes();
		for (int i=0; i < nl.getLength(); i++) {
			Node nd = nl.item(i);
			if (nd.getNodeName().equals(tagName)) {
				return nd;
			}
		}
		return null;
	}
	
	public final List<Node> subNodes(final Node srcDom, final String tagName) {
		List<Node> result = new ArrayList<Node>();
		NodeList nl = srcDom.getChildNodes();
		for (int i=0; i < nl.getLength(); i++) {
			Node nd = nl.item(i);
			if (nd.getNodeName().equals(tagName)) {
				result.add(nd);
			}
		}
		return result;
	}
	
    public final String getNodeAttrib(Node node, String attrib) {
        NamedNodeMap mp = node.getAttributes();
        if (mp == null) {
            return null;
        }
        Node attrNode = mp.getNamedItem(attrib);
        if (attrNode == null) {
            return null;
        }
        return attrNode.getNodeValue();
        
    }
	/**
	 * @param doc
	 *            the document to print
	 */
	public final void printDom(final Document doc) {
		Element element = doc.getDocumentElement();
		log(element.getNodeName());
	}

	/**
	 * @param string
	 *            string to log
	 */
	private void log(final String string) {
		System.out.print(string);
	}
	
	public final String getNodePath(Node node) {
		String path = node.getNodeName();
		Node pn = node.getParentNode();
		while(pn != null && !(pn instanceof Document)) {
			path = pn.getNodeName() + "." + path;
			pn = pn.getParentNode();
		}
		return path;
	}
}
